```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kafka分区机制深度解析 | 技术小馆</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            line-height: 1.8;
            color: #333;
            background-color: #f9fafb;
        }
        h1, h2, h3, h4, h5, h6 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
            color: #111827;
        }
        .hero {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
        }
        .code-block {
            background-color: #2d2d2d;
            color: #f8f8f2;
            border-radius: 8px;
            position: relative;
        }
        .code-block::before {
            content: '';
            position: absolute;
            top: 12px;
            left: 12px;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: #ff5f56;
            box-shadow: 20px 0 #ffbd2e, 40px 0 #27c93f;
        }
        .card {
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }
        .highlight {
            position: relative;
        }
        .highlight::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 30%;
            background-color: rgba(79, 70, 229, 0.2);
            z-index: -1;
            transition: all 0.3s ease;
        }
        .highlight:hover::after {
            height: 100%;
        }
        .diagram-container {
            background-color: #fff;
            border-radius: 12px;
            padding: 24px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <section class="hero text-white py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl">
            <div class="flex flex-col md:flex-row items-center">
                <div class="md:w-1/2 mb-10 md:mb-0">
                    <span class="inline-block px-3 py-1 bg-white text-indigo-600 rounded-full text-sm font-medium mb-4">技术深度</span>
                    <h1 class="text-4xl md:text-5xl font-bold mb-6 leading-tight">Kafka分区机制解析</h1>
                    <p class="text-xl text-indigo-100 mb-8">探索高吞吐量背后的核心架构设计</p>
                    <div class="flex items-center">
                        <i class="fas fa-book-reader text-2xl mr-3"></i>
                        <span class="text-indigo-200">技术小馆 · 分布式系统专题</span>
                    </div>
                </div>
                <div class="md:w-1/2">
                    <div class="relative">
                        <div class="absolute w-full h-full bg-indigo-500 rounded-xl -rotate-6"></div>
                        <div class="relative bg-white text-gray-800 p-6 rounded-xl shadow-lg">
                            <div class="flex mb-3">
                                <div class="w-3 h-3 rounded-full bg-red-500 mr-2"></div>
                                <div class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></div>
                                <div class="w-3 h-3 rounded-full bg-green-500"></div>
                            </div>
                            <div class="font-mono text-sm">
                                <p class="text-indigo-600"># Kafka Topic</p>
                                <p>partitions: <span class="font-bold">3</span></p>
                                <p>replication: <span class="font-bold">2</span></p>
                                <p class="mt-4">producer → partition → consumer</p>
                                <p class="text-indigo-600 mt-4"># High Throughput</p>
                                <p>parallel processing</p>
                                <p>load balancing</p>
                                <p>fault tolerance</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-5xl py-12 px-4">
        <!-- Introduction -->
        <section class="mb-16">
            <p class="text-xl text-gray-600 leading-relaxed mb-8">
                Kafka 的分区机制是其高吞吐量和可扩展性的核心之一。在 Kafka 中，数据是以 <span class="highlight font-bold">Partition</span> 为单位进行分发、存储和处理的。理解 Kafka 的分区机制对于深入掌握其性能优化、容错和负载均衡有重要意义。
            </p>
            
            <div class="bg-blue-50 border-l-4 border-blue-500 p-6 rounded-r-lg mb-8">
                <div class="flex items-start">
                    <i class="fas fa-lightbulb text-blue-500 text-2xl mr-4 mt-1"></i>
                    <div>
                        <h3 class="text-xl font-bold text-blue-800 mb-2">核心概念</h3>
                        <p class="text-blue-700">分区(Partition)是Kafka实现并行处理的基础，每个分区都是一个有序的、不可变的消息序列，新消息不断追加到分区末尾。这种设计使得Kafka能够高效地处理海量数据。</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 1 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">1</span>
                Kafka 分区概述
            </h2>
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <p class="mb-4">Kafka 中的 <span class="highlight font-bold">Partition</span> 是 Kafka 消息系统的基本单元。每个 <span class="highlight font-bold">Topic</span> 可以拥有多个 <span class="highlight font-bold">Partition</span>，Kafka 会将消息按照一定规则分发到这些分区中。每个分区都是一个 <span class="highlight font-bold">日志文件</span>，写入的消息按顺序排列，并且每条消息都有一个唯一的 <span class="highlight font-bold">Offset</span>。</p>
                    <p class="mb-4">Kafka 的分区机制支持水平扩展，多个 <span class="highlight font-bold">Partition</span> 使得 Kafka 可以在多个机器上并行处理消息，从而提升吞吐量。</p>
                    <div class="bg-yellow-50 border-l-4 border-yellow-500 p-4 rounded-r-lg">
                        <div class="flex items-start">
                            <i class="fas fa-exclamation-circle text-yellow-500 mr-3 mt-1"></i>
                            <p class="text-yellow-800">分区数量在创建Topic时指定，之后可以增加但不能减少。合理设置分区数量对系统性能至关重要。</p>
                        </div>
                    </div>
                </div>
                <div class="bg-gray-50 p-6 rounded-lg">
                    <div class="flex items-center mb-4">
                        <i class="fas fa-project-diagram text-indigo-500 mr-2"></i>
                        <h3 class="font-bold">Topic与Partition关系</h3>
                    </div>
                    <div class="mermaid">
                        graph TD
                            A[Topic] --> B[Partition 0]
                            A --> C[Partition 1]
                            A --> D[Partition 2]
                            B --> E[Broker 1]
                            C --> F[Broker 2]
                            D --> G[Broker 3]
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 2 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">2</span>
                分区的创建和管理
            </h2>
            <p class="mb-6">Kafka 的分区是由 <span class="highlight font-bold">Kafka Broker</span> 管理的。在创建一个 <span class="highlight font-bold">Topic</span> 时，Kafka 会为该 <span class="highlight font-bold">Topic</span> 分配多个 <span class="highlight font-bold">Partition</span>，每个 <span class="highlight font-bold">Partition</span> 会有一个或多个 <span class="highlight font-bold">Replica</span>（副本）。分区和副本的分配遵循一定的策略，确保负载均衡和容错性。</p>
            
            <div class="code-block p-6 mb-8 overflow-x-auto">
                <pre class="text-sm"><code>// 创建 Topic 时设置 Partition 数量和副本数
public void createTopic(String topic, int numPartitions, int replicationFactor) {
    // 创建 topic 的分区和副本
    for (int i = 0; i &lt; numPartitions; i++) {
        Partition partition = new Partition(topic, i, replicationFactor);
        partitions.add(partition);
    }
}</code></pre>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="card bg-white p-6 rounded-lg">
                    <div class="flex items-center mb-4">
                        <i class="fas fa-copy text-indigo-500 mr-3"></i>
                        <h3 class="font-bold">分区副本</h3>
                    </div>
                    <p>每个分区可以有多个副本，提高数据可靠性。其中一个副本作为Leader处理所有读写请求，其他副本作为Follower从Leader同步数据。</p>
                </div>
                <div class="card bg-white p-6 rounded-lg">
                    <div class="flex items-center mb-4">
                        <i class="fas fa-balance-scale text-indigo-500 mr-3"></i>
                        <h3 class="font-bold">分配策略</h3>
                    </div>
                    <p>Kafka会尽量将分区和副本均匀分布在不同的Broker上，避免单点过载。默认使用轮询策略进行分配。</p>
                </div>
            </div>
        </section>

        <!-- Section 3 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">3</span>
                消息生产者如何选择分区
            </h2>
            <p class="mb-6">Kafka 消息的生产者根据一定的 <span class="highlight font-bold">Partitioner</span> 规则来决定消息被写入哪个 <span class="highlight font-bold">Partition</span>。默认情况下，Kafka 使用 <span class="highlight font-bold">消息的 Key</span> 来决定分配的分区。如果消息没有 <span class="highlight font-bold">Key</span>，Kafka 会采取轮询的方式来均匀地分配消息到各个分区。</p>
            
            <div class="code-block p-6 mb-8 overflow-x-auto">
                <pre class="text-sm"><code>// 默认的 Partitioner
public class DefaultPartitioner implements Partitioner {
    public int partition(ProducerRecord record, int numPartitions) {
        // 基于消息 Key 的哈希值来决定 Partition
        if (record.key() != null) {
            return Math.abs(record.key().hashCode()) % numPartitions;
        } else {
            // 如果没有 Key，轮询分配
            return Math.abs(record.hashCode()) % numPartitions;
        }
    }
}</code></pre>
            </div>
            
            <div class="bg-green-50 border-l-4 border-green-500 p-6 rounded-r-lg">
                <div class="flex items-start">
                    <i class="fas fa-check-circle text-green-500 text-2xl mr-4 mt-1"></i>
                    <div>
                        <h3 class="text-xl font-bold text-green-800 mb-2">关键点总结</h3>
                        <ul class="list-disc pl-5 text-green-700 space-y-2">
                            <li>相同Key的消息会路由到同一分区，保证消息顺序性</li>
                            <li>无Key消息均匀分布，实现负载均衡</li>
                            <li>自定义Partitioner可以实现特殊分发逻辑</li>
                        </ul>
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 4 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">4</span>
                消费者如何读取分区数据
            </h2>
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <p class="mb-4">Kafka 的消费者通过分配给它的 <span class="highlight font-bold">Partition</span> 来读取消息。在消费者组（<span class="highlight font-bold">Consumer Group</span>）中，每个消费者只会消费自己分配到的 <span class="highlight font-bold">Partition</span>。这意味着，每个消费者会按顺序消费其所在 <span class="highlight font-bold">Partition</span> 中的消息，并在读取完消息后提交 <span class="highlight font-bold">Offset</span>。</p>
                    
                    <div class="code-block p-6 mb-4 overflow-x-auto">
                        <pre class="text-sm"><code>// 消费者从 Partition 中顺序读取消息
public ConsumerRecord poll() {
    ConsumerRecord record = this.partition.poll(); // 按 Offset 顺序读取
    return record;
}</code></pre>
                    </div>
                    
                    <p class="text-sm text-gray-600">消费者读取消息时，按照 <span class="highlight font-bold">Partition</span> 内的 <span class="highlight font-bold">Offset</span> 顺序读取消息，确保消息在每个 <span class="highlight font-bold">Partition</span> 内的顺序性。</p>
                </div>
                <div class="diagram-container">
                    <div class="mermaid">
                        graph LR
                            subgraph Consumer Group
                                C1[Consumer 1] --> P0[Partition 0]
                                C2[Consumer 2] --> P1[Partition 1]
                                C3[Consumer 3] --> P2[Partition 2]
                            end
                            P0 --> B1[Broker 1]
                            P1 --> B2[Broker 2]
                            P2 --> B3[Broker 3]
                    </div>
                </div>
            </div>
        </section>

        <!-- Section 5 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">5</span>
                Partition 副本机制
            </h2>
            <p class="mb-6">为了保证数据的高可用性和容错性，Kafka 为每个 <span class="highlight font-bold">Partition</span> 配置了多个副本（<span class="highlight font-bold">Replica</span>）。副本的 <span class="highlight font-bold">Leader</span> 负责处理所有的读写请求，其他副本充当 <span class="highlight font-bold">Follower</span>，它们会从 <span class="highlight font-bold">Leader</span> 获取最新的数据并同步。</p>
            
            <div class="code-block p-6 mb-8 overflow-x-auto">
                <pre class="text-sm"><code>// Partition 副本同步机制
public void replicate() {
    if (this.isLeader()) {
        for (Replica replica : this.replicas) {
            // 同步消息到 Follower
            replica.syncWithLeader();
        }
    }
}</code></pre>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6">
                <div class="card bg-white p-6 rounded-lg">
                    <div class="flex items-center mb-3">
                        <i class="fas fa-crown text-yellow-500 mr-2"></i>
                        <h4 class="font-bold">Leader</h4>
                    </div>
                    <p class="text-sm">处理所有读写请求，负责数据同步</p>
                </div>
                <div class="card bg-white p-6 rounded-lg">
                    <div class="flex items-center mb-3">
                        <i class="fas fa-users text-blue-500 mr-2"></i>
                        <h4 class="font-bold">Follower</h4>
                    </div>
                    <p class="text-sm">从Leader同步数据，准备成为新Leader</p>
                </div>
                <div class="card bg-white p-6 rounded-lg">
                    <div class="flex items-center mb-3">
                        <i class="fas fa-clipboard-check text-green-500 mr-2"></i>
                        <h4 class="font-bold">ISR</h4>
                    </div>
                    <p class="text-sm">In-Sync Replicas，与Leader保持同步的副本集合</p>
                </div>
            </div>
        </section>

        <!-- Section 6 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">6</span>
                分区的负载均衡
            </h2>
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <p class="mb-4">Kafka 在分区的负载均衡方面做了很多优化。通常情况下，Kafka 会将 <span class="highlight font-bold">Topic</span> 中的 <span class="highlight font-bold">Partition</span> 均匀地分配到各个 <span class="highlight font-bold">Broker</span> 上。在生产者发送消息时，会根据分区策略选择分配的 <span class="highlight font-bold">Partition</span>，而消费者会根据 <span class="highlight font-bold">Consumer Group</span> 中的分配算法来分配各自的 <span class="highlight font-bold">Partition</span>。</p>
                    
                    <div class="code-block p-6 mb-4 overflow-x-auto">
                        <pre class="text-sm"><code>// Kafka 负载均衡策略
public class LoadBalancer {
    public void rebalancePartitions(List&lt;Partition&gt; partitions, List&lt;Consumer&gt; consumers) {
        // 使用负载均衡算法将分区均匀地分配到消费者
        for (int i = 0; i &lt; partitions.size(); i++) {
            Consumer consumer = consumers.get(i % consumers.size());
            consumer.assignPartition(partitions.get(i));
        }
    }
}</code></pre>
                    </div>
                </div>
                <div class="bg-purple-50 p-6 rounded-lg">
                    <div class="flex items-center mb-4">
                        <i class="fas fa-random text-purple-500 mr-3"></i>
                        <h3 class="font-bold">均衡策略优势</h3>
                    </div>
                    <ul class="list-disc pl-5 space-y-2 text-purple-800">
                        <li>生产者端：通过分区策略实现消息的均匀分布</li>
                        <li>消费者端：通过Rebalance机制动态分配分区</li>
                        <li>Broker端：分区副本均匀分布在集群各节点</li>
                        <li>最大化利用集群资源，避免热点问题</li>
                    </ul>
                </div>
            </div>
        </section>

        <!-- Section 7 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">7</span>
                分区的故障恢复与领导者选举
            </h2>
            <p class="mb-6">当一个 <span class="highlight font-bold">Broker</span> 宕机或 <span class="highlight font-bold">Partition</span> 的 <span class="highlight font-bold">Leader</span> 节点失效时，Kafka 会触发 <span class="highlight font-bold">Leader 选举</span>，从 <span class="highlight font-bold">ISR</span> 中选择一个新的 <span class="highlight font-bold">Leader</span>，并将其分配给新的 <span class="highlight font-bold">Broker</span>。这个过程由 <span class="highlight font-bold">Zookeeper</span> 协调，以确保一致性和高可用性。</p>
            
            <div class="code-block p-6 mb-8 overflow-x-auto">
                <pre class="text-sm"><code>// 选举新的 Leader
public void handleLeaderElection() {
    if (this.isLeaderFailed()) {
        // 从 ISR 中选择一个新的 Leader
        Partition newLeader = chooseNewLeader();
        this.leader = newLeader;
    }
}</code></pre>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6">
                <div class="card bg-white p-6 rounded-lg">
                    <h4 class="font-bold mb-3 text-red-600">故障检测</h4>
                    <p class="text-sm">Controller监控Broker心跳，检测节点失效</p>
                </div>
                <div class="card bg-white p-6 rounded-lg">
                    <h4 class="font-bold mb-3 text-blue-600">Leader选举</h4>
                    <p class="text-sm">从ISR中选择第一个副本作为新Leader</p>
                </div>
                <div class="card bg-white p-6 rounded-lg">
                    <h4 class="font-bold mb-3 text-green-600">恢复完成</h4>
                    <p class="text-sm">更新元数据，客户端重定向到新Leader</p>
                </div>
            </div>
        </section>

        <!-- Section 8 -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <span class="w-8 h-8 bg-indigo-600 text-white rounded-full flex items-center justify-center mr-4">8</span>
                分区的扩展性
            </h2>
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <p class="mb-4">Kafka 的分区机制支持动态扩展。当集群负载增加时，可以通过增加 <span class="highlight font-bold">Partition</span> 来提升吞吐量。Kafka 支持在 <span class="highlight font-bold">Topic</span> 创建后，动态增加 <span class="highlight font-bold">Partition</span> 数量。但是，增加分区会导致已有的数据重新平衡，可能会影响系统的性能，因此增加分区通常需要谨慎。</p>
                    
                    <div class="code-block p-6 mb-4 overflow-x-auto">
                        <pre class="text-sm"><code>// 动态增加 Partition 数量
public void addPartitions(String topic, int newPartitions) {
    TopicMetadata topicMetadata = this.getTopicMetadata(topic);
    topicMetadata.increasePartitions(newPartitions);
}</code></pre>
                    </div>
                </div>
                <div class="bg-indigo-50 p-6 rounded-lg">
                    <div class="flex items-center mb-4">
                        <i class="fas fa-expand-alt text-indigo-500 mr-3"></i>
                        <h3 class="font-bold">扩展性考虑</h3>
                    </div>
                    <ul class="list-disc pl-5 space-y-2 text-indigo-800">
                        <li>增加分区需考虑消费者处理能力</li>
                        <li>分区过多会导致更多文件句柄和内存开销</li>
                        <li>最佳实践是根据预期吞吐量预留足够分区</li>
                        <li>监控分区负载，适时调整分区数量</li>
                    </ul>
                </div>
            </div>
        </section>

        <!-- Summary -->
        <section class="mb-16">
            <div class="bg-gradient-to-r from-indigo-500 to-purple-600 text-white p-8 rounded-xl">
                <h2 class="text-2xl font-bold mb-6 flex items-center">
                    <i class="fas fa-star mr-3"></i>
                    Kafka分区机制核心价值
                </h2>
                <div class="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
                    <div class="bg-white bg-opacity-10 p-4 rounded-lg">
                        <div class="text-3xl mb-2"><i class="fas fa-bolt"></i></div>
                        <h4 class="font-bold mb-2">高吞吐量</h4>
                        <p class="text-sm">并行处理多个分区消息</p>
                    </div>
                    <div class="bg-white bg-opacity-10 p-4 rounded-lg">
                        <div class="text-3xl mb-2"><i class="fas fa-expand"></i></div>
                        <h4 class="font-bold mb-2">水平扩展</h4>
                        <p class="text-sm">动态增加分区提升容量</p>
                    </div>
                    <div class="bg-white bg-opacity-10 p-4 rounded-lg">
                        <div class="text-3xl mb-2"><i class="fas fa-shield-alt"></i></div>
                        <h4 class="font-bold mb-2">容错性</h4>
                        <p class="text-sm">副本机制保障数据安全</p>
                    </div>
                    <div class="bg-white bg-opacity-10 p-4 rounded-lg">
                        <div class="text-3xl mb-2"><i class="fas fa-balance-scale-right"></i></div>
                        <h4 class="font-bold mb-2">负载均衡</h4>
                        <p class="text-sm">均匀分布消息处理压力</p>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="container mx-auto max-w-5xl px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-6 md:mb-0">
                    <h3 class="text-xl font-bold text-white mb-2">技术小馆</h3>
                    <p class="text-gray-400">探索技术原理，分享架构实践</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="text-indigo-300 hover:text-white transition duration-300 flex items-center">
                        <i class="fas fa-external-link-alt mr-2"></i>
                        <span>访问技术小馆</span>
                    </a>
                </div>
            </div>
            <div class="border-t border-gray-800 mt-8 pt-8 text-center text-gray-500 text-sm">
                <p>© 2023 技术小馆. 保留所有权利.</p>
            </div>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            fontFamily: 'Noto Sans SC, sans-serif',
            flowchart: {
                useMaxWidth: false,
                htmlLabels: true,
                curve: 'basis'
            }
        });
        
        // 卡片悬停效果
        const cards = document.querySelectorAll('.card');
        cards.forEach(card => {
            card.addEventListener('mouseenter', () => {
                card.style.transform = 'translateY(-5px)';
                card.style.boxShadow = '0 10px 15px rgba(0, 0, 0, 0.1)';
            });
            card.addEventListener('mouseleave', () => {
                card.style.transform = 'translateY(0)';
                card.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.05)';
            });
        });
        
        // 高亮效果
        const highlights = document.querySelectorAll('.highlight');
        highlights.forEach(hl => {
            hl.addEventListener('mouseenter', () => {
                hl.style.transition = 'all 0.3s ease';
            });
        });
    </script>
</body>
</html>
```